]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
background: fix asynchronous management of background loading operations
authorLionel Landwerlin <llandwerlin@gmail.com>
Mon, 24 Jun 2013 18:13:05 +0000 (19:13 +0100)
committerLionel Landwerlin <llandwerlin@gmail.com>
Wed, 3 Jul 2013 16:03:02 +0000 (17:03 +0100)
This fixes a blue background being drawn when switching the monitors
configuration using hardware keys
(clone/multimonitor/external/internal).

The problem is that the shell gather all background loading requests
under the same meta_background_load_file_async call using one
GCancellable (the first one to come). So when the shell receives a
batch of 12 or so XRandr events, it creates 12 new background managers
which end up trying to load 12 times the same background picture. All
of these requests are batched into the same
meta_background_load_file_async using the first GCancellable received
on the first request. Unfortunately, when the first request is
cancelled by the following event indicating a new monitor setup, all
of the background picture requests are dropped on the floor, and
nothing gets loaded (hence the blue screen background).

https://bugzilla.gnome.org/show_bug.cgi?id=703001

js/ui/background.js

index 1d9ab7c210395a480ddbc0afff3d153844a66e46..13343c6c8cea0a18b401d0b3ed9a978a8e2251a2 100644 (file)
@@ -142,33 +142,40 @@ const BackgroundCache = new Lang.Class({
                                         cancellable: null,
                                         onFinished: null });
 
-        for (let i = 0; i < this._pendingFileLoads.length; i++) {
-            if (this._pendingFileLoads[i].filename == params.filename &&
-                this._pendingFileLoads[i].style == params.style) {
-                this._pendingFileLoads[i].callers.push({ shouldCopy: true,
-                                                         monitorIndex: params.monitorIndex,
-                                                         effects: params.effects,
-                                                         onFinished: params.onFinished });
-                return;
-            }
+        let fileLoad = { filename: params.filename,
+                         style: params.style,
+                         shouldCopy: false,
+                         monitorIndex: params.monitorIndex,
+                         effects: params.effects,
+                         onFinished: params.onFinished,
+                         cancellable: new Gio.Cancellable(), };
+        this._pendingFileLoads.push(fileLoad);
+
+        if (params.cancellable) {
+            params.cancellable.connect(Lang.bind(this, function(c) {
+               fileLoad.cancellable.cancel();
+            }));
         }
 
-        this._pendingFileLoads.push({ filename: params.filename,
-                                      style: params.style,
-                                      callers: [{ shouldCopy: false,
-                                                  monitorIndex: params.monitorIndex,
-                                                  effects: params.effects,
-                                                  onFinished: params.onFinished }] });
-
         let content = new Meta.Background({ meta_screen: global.screen,
                                             monitor: params.monitorIndex,
                                             effects: params.effects });
 
         content.load_file_async(params.filename,
                                 params.style,
-                                params.cancellable,
+                                fileLoad.cancellable,
                                 Lang.bind(this,
                                           function(object, result) {
+                                              if (fileLoad.cancellable.is_cancelled()) {
+                                                  if (params.cancellable && params.cancellable.is_cancelled()) {
+                                                      if (params.onFinished)
+                                                          params.onFinished(null);
+                                                      this._removePendingFileLoad(fileLoad);
+                                                      return;
+                                                  }
+                                                  return;
+                                              }
+
                                               try {
                                                   content.load_file_finish(result);
 
@@ -178,22 +185,25 @@ const BackgroundCache = new Lang.Class({
                                                   content = null;
                                               }
 
+                                              let needsCopy = false;
                                               for (let i = 0; i < this._pendingFileLoads.length; i++) {
                                                   let pendingLoad = this._pendingFileLoads[i];
                                                   if (pendingLoad.filename != params.filename ||
                                                       pendingLoad.style != params.style)
                                                       continue;
 
-                                                  for (let j = 0; j < pendingLoad.callers.length; j++) {
-                                                      if (pendingLoad.callers[j].onFinished) {
-                                                          if (content && pendingLoad.callers[j].shouldCopy) {
-                                                              content = object.copy(pendingLoad.callers[j].monitorIndex,
-                                                                                    pendingLoad.callers[j].effects);
-
-                                                          }
+                                                  if (pendingLoad.cancellable.is_cancelled())
+                                                      continue;
 
-                                                          pendingLoad.callers[j].onFinished(content);
+                                                  pendingLoad.cancellable.cancel();
+                                                  if (pendingLoad.onFinished) {
+                                                      if (content && needsCopy) {
+                                                          content = object.copy(pendingLoad.monitorIndex,
+                                                                                pendingLoad.effects);
                                                       }
+
+                                                      needsCopy = true;
+                                                      pendingLoad.onFinished(content);
                                                   }
 
                                                   this._pendingFileLoads.splice(i, 1);
@@ -201,6 +211,15 @@ const BackgroundCache = new Lang.Class({
                                           }));
     },
 
+    _removePendingFileLoad: function(fileLoad) {
+        for (let i = 0; i < this._pendingFileLoads.length; i++) {
+            if (this._pendingFileLoads[i].cancellable == fileLoad.cancellable) {
+                this._pendingFileLoads.splice(i, 1);
+                break;
+            }
+        }
+    },
+
     getImageContent: function(params) {
         params = Params.parse(params, { monitorIndex: 0,
                                         style: null,